﻿#include "BleDevice.h"
#include <QDebug>
#include <QTimer>
#include <QThread>

#include "comm_impl.h"
#include "ufw_protocol.h"

#include "cfdl_ptl_impl.h"
#include "cfdl_login.h"

#include "factory_model.h"
#include "dev_ptl_model.h"

REGISGER_PTL(CFDLPtlImpl, "CFDLptl");
REGISGER_PTL(ufw_protocol, "UFWptl");

static const unsigned int CRC32S_Tab[] = 	//软件CRC32计算码
{
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
//crc32初始值为0xFFFFFFFF, 以下函数为分段校验调用，初始值需要手动设置
void crc_32_sum_trans(uint32_t *check, uint8_t *pData, uint32_t nData)
{
    uint32_t crcVal32 = *check;

    for(uint32_t i = 0; i < nData; i++)
    {
        crcVal32 = ((crcVal32 >> 8) & 0x00FFFFFF) ^ CRC32S_Tab[(crcVal32^ pData[i]) & 0xFF];
    }

    *check = crcVal32;
}

BleDevice::BleDevice(QObject *parent) :
    QObject(parent),
    mBleCtrl(nullptr),
    mBleService(nullptr)
{
    mDevDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
    mDevDiscoveryAgent->setLowEnergyDiscoveryTimeout(120000);

    connect(this, &BleDevice::bleSignalLog, UsrCommImpl::Instance(), &UsrCommImpl::CommSlotLog);
    connect(mDevDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BleDevice::slotDevDiscovered); //[this]() {qDebug() << "find a new dev";});

    connect(mDevDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, [this]() {
        bleSearchFlag = false;
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble search finished");
        emit bleStatus(BLESearchStop);
    });

    timer = new QTimer(this);
    timer->setInterval(10);
    timer->start();

    _ptl = FactoryPtlModel::produce("CFDLptl");
    _ptl->register_send_fun(std::bind(&BleDevice::sendData_buf,
                                      this, std::placeholders::_1, std::placeholders::_2));

    _ptl->register_cmd_module(0x0000,
                                 std::bind(&cfdl_login::cfdl_msg_cb,  cfdl_login::Instance(), std::placeholders::_1),
                                 std::bind(&cfdl_login::cfdl_msg_err, cfdl_login::Instance(), std::placeholders::_1));

    connect(timer, &QTimer::timeout, this, &BleDevice::SlotTimer);
}

BleDevice::~BleDevice()
{
    delete _ptl;
}

BleDevice* BleDevice::Instance()
{
    static BleDevice ble;

    return &ble;
}

void BleDevice::SlotTimer()
{
    //if(bNotifyFlag)
    //    mBleService->readDescriptor(ble_notify);
    #if 0
    if(bRxWrite) {
        uint8_t senddata[4] = {0x11, 0x22, 0x33, 0x44};
        QByteArray tmp = QByteArray((char *)senddata, 4);
        sendData(tmp);
    }
    #endif

#if !USE_CFDL
    static uint32_t index = 0, tick_trans = 0, tick = 0;
    if(m_IsTrans) {
        if(++tick >= 20) {
            tick = 0;
            uint32_t tmp = transPtl->file_trans_index();
            if(tmp > index) {
                index = tmp;
                emit SignalUpdateProgress(index);
            }

            if(transPtl->is_file_trans_end()) {
                //jl_ptl_blinkme_file_trans_end(0);
                m_IsTrans = false;
                emit SignalUpdateProgress(slice_num);
                emit bleStatus(BLETransEnd);
            }
        }

        #if !JL_PTL_ACK_TRANS
        if(transPtl->file_trans_state() == FILE_TRANS_SLICE) {
            //if(++tick_trans >= 2)
            {
                tick_trans = 0;
                transPtl->file_trans_slice_period();
            }
        }
        #endif
    }
    else {
        index = 0;
        tick = 0;
        tick_trans = 0;
    }

    transPtl->jl_ptl_run(10);
#else
    if(bTxNotify)  {
        _ptl->ptl_run(10);
    }
#endif
}

bool BleDevice::isBleConnect()
{
    return bleConnFlag;
}

bool BleDevice::isBleSearch()
{
    return bleSearchFlag;
}

void BleDevice::bleSearchStart()
{
    if(bleConnFlag) return;

    if (!mDevDiscoveryAgent->isActive()) {
        mDevDiscoveryAgent->start();
        bleSearchFlag = true;
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble start searched!");
        emit bleStatus(BLESearchStart);
    }
}

void BleDevice::bleSearchStop()
{
    if(!bleSearchFlag) return;

    bleSearchFlag = false;
    mDevDiscoveryAgent->stop();
}

void BleDevice::bleDisconnet()
{
    bleSearchFlag = false;
    bleConnFlag   = false;
    bTxNotify = false;
    bRxWrite  = false;
    if(mBleCtrl) {
        mBleCtrl->disconnectFromDevice();
    }

}

void BleDevice::bleConnect(const QString &name)
{
    //if(bleSearchFlag) return;
    mDevDiscoveryAgent->stop();
    bleSearchFlag = false;

    QList<QBluetoothDeviceInfo> dev_list;
    dev_list = mDevDiscoveryAgent->discoveredDevices();

    bool dev_not_find = true;
    QList<QBluetoothDeviceInfo>::iterator it;
    for(it=dev_list.begin(); it != dev_list.end(); it++) {
        QBluetoothDeviceInfo dev = *it;
        if(name == dev.name()
            && dev.coreConfigurations() == QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
            recorderSearched(dev);
            dev_not_find = false;
            break;
        }
    }

    if(dev_not_find) {
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "not finded recorder");
        emit bleStatus(BLEDisconnect);
    }
}

void BleDevice::slotDevDiscovered(const QBluetoothDeviceInfo& info)
{
    QString type;
    switch(info.coreConfigurations())
    {
    case QBluetoothDeviceInfo::UnknownCoreConfiguration:
        type = "UnknowBLE"; break;
    case QBluetoothDeviceInfo::LowEnergyCoreConfiguration:
        type = " LowBLE"; break;
    case QBluetoothDeviceInfo::BaseRateCoreConfiguration:
        type = "BaseBLE"; break;
    case QBluetoothDeviceInfo::BaseRateAndLowEnergyCoreConfiguration:
        type = "Base&LowBLE"; break;
    }

    if(info.name().indexOf("Bluetooth") == 0) return;

    //use multi-arg instead
    QString tmp = QString(" %1 [%2]").arg(info.name()).arg(info.address().toString());
    emit bleSignalLog(UsrCommImpl::logDateTime, type, tmp);

    emit signalBleInfo(info.name(), info.address().toString());
}

void BleDevice::recorderSearched(QBluetoothDeviceInfo& recorder)
{
    emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble connecting...");

    mBleCtrl = QLowEnergyController::createCentral(recorder, this);

    connect(mBleCtrl, &QLowEnergyController::connected, this, [this]() {
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble connected!");

        bleConnFlag = true;
        emit bleStatus(BLEConnect);
        mBleCtrl->discoverServices();
    });

    connect(mBleCtrl, &QLowEnergyController::disconnected, this, [this]() {
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble disconnected!");
        bleConnFlag = false;
        m_IsTrans = false;
        emit bleStatus(BLEDisconnect);
        //RecordFile::Instance()->setConnType(CONTYPE_NONE);
    });

    connect(mBleCtrl, &QLowEnergyController::discoveryFinished, this, [this]() {
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble discoveryFinished");
    });

    connect(mBleCtrl, &QLowEnergyController::mtuChanged, this, [this](int mtu) {
        emit bleSignalLog(UsrCommImpl::logDateTime, "BLE changed MTU:", QString::number(mtu));
    });

    connect(mBleCtrl, &QLowEnergyController::serviceDiscovered, this, &BleDevice::slotRecorderDiscovered);

    mBleCtrl->connectToDevice();
}

void BleDevice::slotRecorderDiscovered(QBluetoothUuid uuid)
{
    qDebug() << "recorder uuid: " << uuid;
    QString uuid_str = uuid.toString();
    emit signalBleUUID(uuid_str);
    emit bleSignalLog(UsrCommImpl::logDateTime, "UUID:", uuid_str);

    //QBluetoothUuid ble_uuid = QBluetoothUuid(uuid);
    //d8528400-66f0-40ff-8f3d-bc7a9853e04a
    uuid_str = uuid_str.toLower();
    if(uuid_str.indexOf("bc7a9853e04a") >= 0) {
        QThread::msleep(100);
        dev_uuid = uuid;
        mBleService = mBleCtrl->createServiceObject(uuid, this);
        if(!mBleService) {
            emit bleSignalLog(UsrCommImpl::logDateTime, "ERR:", "ble createServiceObject failed!");
            return;
        }
        //service state
        connect(mBleService, &QLowEnergyService::stateChanged, this,
            &BleDevice::slotRecorderStateChanged);
        connect(mBleService, &QLowEnergyService::errorOccurred, this, &BleDevice::slotBleError);

        if(mBleService->state() == QLowEnergyService::RemoteService)
            mBleService->discoverDetails();
    }
}

void BleDevice::slotRecorderStateChanged(QLowEnergyService::ServiceState state)
{
    if(state == QLowEnergyService::RemoteServiceDiscovered) {
        emit bleSignalLog(UsrCommImpl::logDateTime, nullptr, "ble ServiceDiscovered!");
        QThread::msleep(100);
        recorderSearchService();
    }
}

void BleDevice::slotRecorderCharacteristicChanged(const QLowEnergyCharacteristic &info,
                                                  const QByteArray &value)
{
    Q_UNUSED(info);

    if (value.length() <= 0) {
        return;
    }

    QString log = UsrCommImpl::byteArrayToHexStr(value);
    emit bleSignalLog(UsrCommImpl::logDateTime, "RECV:", log);

    uint32_t rlen = static_cast<uint16_t>(value.length());
    char *pData = const_cast<char *>(value.data()) ;

    _ptl->ptl_io_in((uint8_t *)pData, rlen);
    //RecordFile::Instance()->recorder_ptl_keepRecv(log, reinterpret_cast<uint8_t *>(pData), rlen);
}

void BleDevice::slotRecorderCharacteristicRead(const QLowEnergyCharacteristic& info, const QByteArray& value)
{
    Q_UNUSED(info);
    emit bleSignalLog(UsrCommImpl::logDateTime, ">>ble read:", QString::number(value.length()));
}

void BleDevice::slotRecorderCharacteristicWrite(const QLowEnergyCharacteristic& info, const QByteArray& value)
{
    Q_UNUSED(info);
    Q_UNUSED(value);

    //QString log = UsrCommImpl::byteArrayToHexStr(value);
    //emit bleSignalLog(UsrCommImpl::logDateTime, "RECV1:", log);

    //emit bleSignalLog(UsrCommImpl::logDateTime, ">>ble write:", QString::number(value.length()));
}

void BleDevice::recorderSearchService()
{
    QList<QLowEnergyCharacteristic> chlist = mBleService->characteristics();
    quint32 index = 0;

    foreach(QLowEnergyCharacteristic c, chlist) {
        index++;
        if(!c.isValid()) continue;

        QLowEnergyCharacteristic::PropertyTypes p = c.properties();
        if((p & QLowEnergyCharacteristic::WriteNoResponse) && (p & QLowEnergyCharacteristic::Notify)) {
            m_ChCtrlNotifyWrite = c;
            emit bleSignalLog(UsrCommImpl::logDateTime, "CTRL>>", m_ChCtrlNotifyWrite.uuid().toString());
        }
        else if((p & QLowEnergyCharacteristic::WriteNoResponse) && (p & QLowEnergyCharacteristic::Write)) {
            m_ChRxWrite = c;
            bRxWrite = true;
            emit bleSignalLog(UsrCommImpl::logDateTime, "  RX>>", m_ChRxWrite.uuid().toString());
        }
        else if(p & QLowEnergyCharacteristic::Notify) {
            m_ChTxNotify = c;
            emit bleSignalLog(UsrCommImpl::logDateTime, "  TX>>", m_ChTxNotify.uuid().toString());
        }

        qDebug() << index << " characteristic c" << p;
    }

    //PreCondition: service details already discovered
    QLowEnergyCharacteristic txx = mBleService->characteristic(m_ChTxNotify.uuid());
    if (!txx.isValid()) {
        emit bleSignalLog(UsrCommImpl::logDateTime, ">>", "txx is invalid!");
        return;
    }

    QLowEnergyDescriptor notification = txx.clientCharacteristicConfiguration();
    if (!notification.isValid()){
        emit bleSignalLog(UsrCommImpl::logDateTime, ">>", "notification is invalid!");
        return;
    }

    // establish hook into notifications
    //connect(mBleService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),
    //        this, SLOT(slotRecorderCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));

    connect(mBleService, &QLowEnergyService::characteristicChanged, this,
            &BleDevice::slotRecorderCharacteristicChanged);
    connect(mBleService, &QLowEnergyService::characteristicRead, this,
            &BleDevice::slotRecorderCharacteristicRead);
    connect(mBleService, &QLowEnergyService::characteristicWritten, this,
            &BleDevice::slotRecorderCharacteristicWrite);

    // enable notification
    mBleService->writeDescriptor(notification, QByteArray::fromHex("0100"));
    tx_descriptor = notification;
    bTxNotify = true;

    emit bleSignalLog(UsrCommImpl::logDateTime, "CX UUID:", notification.uuid().toString());
#if 0

    QList<QLowEnergyDescriptor> crList;
    #if 0
    crList = m_ChCtrlNotifyWrite.descriptors();
    foreach (QLowEnergyDescriptor c, crList) {
        if(c.isValid()) {
            notify_descriptor = c;
            bCtrlNotify = true;
            emit bleSignalLog(UsrCommImpl::logDateTime, ">>", "notify_descriptor is valid!");
            emit bleSignalLog(UsrCommImpl::logDateTime, "UUID:", c.uuid().toString());
            mBleService->writeDescriptor(notify_descriptor, QByteArray::fromHex("0100")); //attr u16 0001
        }
    }

    crList = m_ChRxWrite.descriptors();
    foreach (QLowEnergyDescriptor c, crList) {
        if(c.isValid()) {
            rx_descriptor = c;
            mBleService->writeDescriptor(rx_descriptor, QByteArray::fromHex("0100")); //attr u16 0001
            emit bleSignalLog(UsrCommImpl::logDateTime, ">>", "rx_descriptor is valid!");
            emit bleSignalLog(UsrCommImpl::logDateTime, "UUID:", c.uuid().toString());
        }
    }
    #endif

    QThread::msleep(100);

    crList = m_ChTxNotify.descriptors();
    foreach (QLowEnergyDescriptor c, crList) {
        if(c.isValid()) {
            tx_descriptor = c;
            bTxNotify = true;
            emit bleSignalLog(UsrCommImpl::logDateTime, ">>", "tx_descriptor is valid!");
            emit bleSignalLog(UsrCommImpl::logDateTime, "CX UUID:", c.uuid().toString());
            emit bleSignalLog(UsrCommImpl::logDateTime, "TX UUID:", m_ChTxNotify.uuid().toString());
            break;
        }
    }

    QThread::msleep(100);
    //characteristicChanged
    connect(mBleService, &QLowEnergyService::characteristicChanged, this,
            &BleDevice::slotRecorderCharacteristicChanged);
    connect(mBleService, &QLowEnergyService::characteristicRead, this,
            &BleDevice::slotRecorderCharacteristicRead);
    connect(mBleService, &QLowEnergyService::characteristicWritten, this,
            &BleDevice::slotRecorderCharacteristicWrite);

    QString tmp = QString("BLE MTU: %1").arg(mBleCtrl->mtu());
    emit bleSignalLog(UsrCommImpl::logDateTime, ">>", tmp);

    QThread::msleep(100);
    BLETxNotify(true);
    //RecordFile::Instance()->setConnType(CONTYPE_BLE);
#endif
}

void BleDevice::sendData(const QByteArray &data)
{
    if(!bleConnFlag || !bRxWrite) return;

    if(mBleService) {
#if USE_CFDL
        mBleService->writeCharacteristic(m_ChRxWrite, data);
#else
        #if !JL_PTL_ACK_TRANS
        if(transPtl->file_trans_index() == 0)
            mBleService->writeCharacteristic(m_ChRxWrite, data);
        else
            mBleService->writeCharacteristic(m_ChRxWrite, data, QLowEnergyService::WriteWithoutResponse);
        #else
        mBleService->writeCharacteristic(m_ChRxWrite, data);
        #endif
#endif
    }
}

void BleDevice::sendData_buf(const char* data, uint16_t data_len)
{
    QByteArray tmp = QByteArray(data, data_len);

    sendData(tmp);
}

void BleDevice::slotBleError(QLowEnergyService::ServiceError error)
{
    if(error == QLowEnergyService::DescriptorReadError) {
        emit bleSignalLog(UsrCommImpl::logDateTime, "descriptorReaderr", "error");
    }

    qDebug() << error;
}

void BleDevice::BLETxNotify(bool enable)
{
    //实时录音流
    if(bTxNotify) {
        if(enable)
            mBleService->writeDescriptor(tx_descriptor, QByteArray::fromHex("0100")); //attr u16 0001
        else
            mBleService->writeDescriptor(tx_descriptor, QByteArray::fromHex("0000")); //attr u16 0000
    }
}

void BleDevice::updateFirmware(const QByteArray& rawBin, quint16 segment, const QString& suffix)
{
    if(!bleConnFlag) return;

    char sbuf[32] = {0};

    int flen = rawBin.length();

    memcpy(sbuf, suffix.toStdString().c_str(), 3);
    sbuf[4] = flen >> 24;
    sbuf[5] = flen >> 16;
    sbuf[6] = flen >> 8;
    sbuf[7] = flen;

    uint32_t check = 0xFFFFFFFF;
    crc_32_sum_trans(&check, (uint8_t *)rawBin.data(), flen);
    sbuf[28] = check >> 24;
    sbuf[29] = check >> 16;
    sbuf[30] = check >> 8;
    sbuf[31] = check;

    static char fileData[1024 * 1024 * 2] = {0};
    memcpy(fileData, sbuf, 32);
    memcpy(fileData + 32, rawBin.data(), flen);

    flen += 32;
    #if USE_CFDL

    #else
    transPtl->trans_file_data_push((uint8_t *)fileData, flen);
    transPtl->file_trans_start(flen, segment);
    #endif
    slice_size = segment;
    slice_num  = flen / segment + (flen % segment > 0);
    slice_index = 0;

    m_IsTrans = true;
}
